#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <signal.h>
/* socket文件描述符 */
int sock_fd;
static void sig_usr(int signum)
{
	if (signum == SIGINT)
	{
		printf("close socket\n");
		close(sock_fd);
		exit(0);
	}
	else
	{
		printf("signal %d received\n", signum);
	}
}
int main(int argc, char *argv[])
{
	if (3 != argc)
	{
		printf("usage: %s serverip port\n", argv[0]);
		return -1;
	}
	char serverip[32] = {0};
	int port = atoi(argv[2]);
	strncpy(serverip, argv[1], sizeof(serverip) - 1);
	printf("server ip is %s\n", serverip);

	struct sigaction sa_usr;
	sa_usr.sa_flags = 0;
	sa_usr.sa_handler = sig_usr;
	sigaction(SIGINT, &sa_usr, NULL);

	/* 建立udp socket */
	sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock_fd < 0)
	{
		perror("socket");
		exit(1);
	}

	/* 设置address */
	struct sockaddr_in addr_serv;
	int len;
	memset(&addr_serv, 0, sizeof(addr_serv));
	addr_serv.sin_family = AF_INET;
	addr_serv.sin_addr.s_addr = inet_addr(serverip);
	addr_serv.sin_port = htons(port);
	len = sizeof(addr_serv);

	int send_num;
	int recv_num;
	char send_buf[20] = "OK";
	char recv_buf[4 * 1024]; // 8kb

	printf("client send: %s\n", send_buf);

	send_num = sendto(sock_fd, send_buf, strlen(send_buf), 0, (struct sockaddr *)&addr_serv, len);

	if (send_num < 0)
	{
		perror("sendto error:");
		printf("run the server first\n");
		exit(1);
	}
	struct timeval tv_begin, tv_end;
	int recv_total = 0;
	gettimeofday(&tv_begin, NULL);
	printf("start test udp speed ...\n");
	//udp 10s timeout
	struct timeval tv_out;
	tv_out.tv_sec = 10;
	tv_out.tv_usec = 0;
	setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, &tv_out, sizeof(tv_out));
	while (1)
	{

		recv_num = recvfrom(sock_fd, recv_buf, sizeof(recv_buf), 0, (struct sockaddr *)&addr_serv, (socklen_t *)&len);

		if (recv_num < 0)
		{
			perror("recvfrom error:");
			exit(1);
		}
		recv_total += recv_num;
		if (recv_total > 1024 * 1024) // 1MByte
		{
			gettimeofday(&tv_end, NULL);
			// convert to kB per second.
			float speed = recv_total / ((tv_end.tv_sec * 1000 + tv_end.tv_usec / 1000) - (tv_begin.tv_sec * 1000 + tv_begin.tv_usec / 1000)); // kbytes/s
			printf("speed is %f kB/s\n", speed);
			memset(&tv_begin, 0, sizeof(tv_begin));
			memset(&tv_end, 0, sizeof(tv_end));
			recv_total = 0;
			gettimeofday(&tv_begin, NULL);
		}
	}
	close(sock_fd);

	return 0;
}